
using System;
using System.Collections.Generic;

using Anculus.Core;

namespace Galaxium.Protocol
{
	public class PriorityQueue<T>
	{
		private LinkedList<T> _highQueue;
		private LinkedList<T> _mediumQueue;
		private LinkedList<T> _lowQueue;
		
		public LinkedList<T> HighQueue
		{
			get { return _highQueue; }
		}
		
		public LinkedList<T> MediumQueue
		{
			get { return _mediumQueue; }
		}
		
		public LinkedList<T> LowQueue
		{
			get { return _lowQueue; }
		}
		
		public int Count
		{
			get
			{
				return _highQueue.Count + _mediumQueue.Count + _lowQueue.Count;
			}
		}
		
		public PriorityQueue ()
		{
			_highQueue = new LinkedList<T> ();
			_mediumQueue = new LinkedList<T> ();
			_lowQueue = new LinkedList<T> ();
		}
		
		public void Enqueue (T obj, PriorityLevel level)
		{
			switch (level)
			{
				case PriorityLevel.Low:
					_lowQueue.AddLast (obj);
					break;
				case PriorityLevel.Medium:
					_mediumQueue.AddLast (obj);
					break;
				case PriorityLevel.High:
					_highQueue.AddLast (obj);
					break;
			}
		}
		
		public T Dequeue ()
		{
			if (_highQueue.Count > 0)
			{
				T val = _highQueue.First.Value;
				_highQueue.RemoveFirst ();
				return val;
			}
			else if (_mediumQueue.Count > 0)
			{
				T val = _mediumQueue.First.Value;
				_mediumQueue.RemoveFirst ();
				return val;
			}
			else if (_lowQueue.Count > 0)
			{
				T val = _lowQueue.First.Value;
				_lowQueue.RemoveFirst ();
				return val;
			}
			else
				return default (T);
		}
		
		public T Peek ()
		{
			if (_highQueue.Count > 0)
				return _highQueue.First.Value;
			else if (_mediumQueue.Count > 0)
				return _mediumQueue.First.Value;
			else if (_lowQueue.Count > 0)
				return _lowQueue.First.Value;
			else
				return default (T);
		}
		
		public bool Remove (T val)
		{
			if (_highQueue.Contains (val))
			{
				return _highQueue.Remove (val);
			}
			else if (_mediumQueue.Contains (val))
			{
				return _mediumQueue.Remove (val);
			}
			else if (_lowQueue.Contains (val))
			{
				return _lowQueue.Remove (val);
			}
			else
				return false;
		}
	}
}
